package graph_viewer.structure.builder;

import java.awt.*;
import java.io.*;
import java.util.*;

import graph_viewer.app_exception.*;
import graph_viewer.drawer.*;
import graph_viewer.factory.*;
import graph_viewer.structure.*;
import graph_viewer.util.*;

/**
Sample of App Format file:
sample.gvr

[node]
0,ECperfBeans
1,mfg
2,supplier
1_1,LargeOrderSes
1_2,WorkOrderSes
2_1,BuyerSes
2_2,ReceiverSes
2_3,SupplierEnt

[relation]
#	node	parent
0,-
1,0
2,0
1_1,1
1_2,1
2_1,2
2_2,2
2_3,2

[edge]
#	from,to
1_1,1_2
1_2,2_1

~

*/
public class App_Format_Graph_Builder extends Basic_Builder{
	public static void main(String arg[])  throws IOException{
		/*
		String data_file_name	= //"6_0_disconnected.spr";
											//"small.cls";
											"28_5_no_position.spr";
											//"c488_mod.gvr";
		String delete_node_label	= //	"3";
													"Cluster_1";
												//"2";
												//"1";
		*/
		String 
			data_file_name		= arg[0],
			delete_node_label		= arg[1];
		
		Graph_Factory				gf		= new Graph_Factory( );
		
		//Debug.println( "Building Orignal graph...", 2 );
		Graph	 c_g					= gf.create( data_file_name, Visual_Component.CLUSTERED_GRAPH );		
		
		App_Format_Graph_Builder sfgb	= new App_Format_Graph_Builder();

		/*c_g.traverse(
			new Command(){
				public void do_action( Node node ){
					Debug.println( "\t[ " + node + " ]", 3 );
				}
			} 
		);*/	



		Debug.println( "ddelete_node_label: " + delete_node_label ,3  );
		Node delete_node	= c_g.search( delete_node_label );

		Debug.println( "the node " + delete_node + "'s desc to be deleted",3  );
		ArrayList descedants	 = c_g.find_tree().find_descedants( delete_node );

		for ( Iterator _i = descedants.iterator(); _i.hasNext(); ){
			Node desc	= (Node)_i.next();

			//c_g.update_related_cluster_edges( desc, delete_node );
			c_g.delete_related_cluster_edges( desc );
			c_g.delete_node( desc );
		}/**/

		String cp_file_name	= data_file_name + ".cp_";

		sfgb.build_data( c_g, cp_file_name );
	}	

	private File	node_data;

	final	private String
		SEP		= ",",
		NODE		= "[node]",
		CHILD_PARENT_RELATION	 = "[relation]",
		EDGE		= "[edge]";

	//============================================================================
	// constructor
	//============================================================================	
	public App_Format_Graph_Builder(){}

	public App_Format_Graph_Builder( String a_file_name ) throws IOException{
		this( new File(a_file_name) );		
	}

	public App_Format_Graph_Builder( File a_file ) throws IOException{
		if ( is_valid_data_file(a_file) ){
			set_file( a_file );
			//Debug.println( " File is NOT null " , 2);
		} else {
			Debug.println( " File is null " , 2);
			node_data	= null;
		}
	}

	//============================================================================
	// setter&getter
	//============================================================================
	public void set_file( String a_file_name ) throws IOException{
		set_file( new File(a_file_name) );
	}

	public void set_file( File a_file ){
		node_data	= a_file;
	}

	public File get_file(){
		return this.node_data;
	}
	//============================================================================
	// public methods
	//============================================================================
	//build graph section//=============================================================
	public Graph build_clustered_graph( Tree a_dummy_tree ) throws IOException {
		Tree created_cluster_tree	 = build_tree( a_dummy_tree );

		Clustered_Graph	a_c_g	= new Clustered_Graph( created_cluster_tree );
		ArrayList				edges		= build_edges( a_c_g );
		a_c_g.set_edges( edges );

		return a_c_g;
	}
	
	
	//the first element of collection must be the node
	public Tree build_tree( Tree a_dummy_tree ) throws IOException{	
		//Debug.println( "Building node", 3 );
		ArrayList node_list = build_nodes();

		//Debug.println( "Building parent_children_relation", 3 );
		build_parent_children_relation( node_list );

		//Debug.println("====================build_tree==================================", 2 );

		Tree created_tree = new Generic_Tree( node_list );
		
		ArrayList clone_node_list	= new ArrayList( node_list );
		for ( Iterator _i = clone_node_list.iterator(); _i.hasNext(); ){
			Node node	= (Node)_i.next();

			if ( node.get_parent() == null ){
				Node root	= created_tree.search( node.get_label() );
				
				created_tree.set_root( root );

				break;
			}
		}
		//to-do: node position
		//Debug.println("===================build_tree end==================================", 2);
		
		return created_tree;
	}

	public ArrayList build_edges( Graph a_dummy_graph ) throws IOException{
		ArrayList edge_lists			= new ArrayList();

		ArrayList	 edge_info_lists	= create_information_list_by_category( this.node_data, EDGE );

		for ( Iterator _i = edge_info_lists.iterator(); _i.hasNext(); ){
			String edge_list	= (String)_i.next();

			String[] edge	= parse_a_pair_of_word( edge_list, SEP );

			edge_lists.add( edge );
		}	
		
		return edge_lists;
	}
	
	//============================================================================
	// private methods
	//============================================================================
	// returned nodes are closed
	private ArrayList build_nodes(){
		ArrayList node_lists			= new ArrayList();

		ArrayList	 node_info_lists	= create_information_list_by_category( this.node_data, NODE );
		
		for ( Iterator _i = node_info_lists.iterator(); _i.hasNext(); ){
			String node_list		= (String)_i.next();
			//Debug.println( "node_list: " + node_list, 3 );

			String[] node_pair	=  parse_a_pair_of_word( node_list, SEP );
			
			Node a_node	= new Node( node_pair[0] );
			a_node.set_is_closed( true );
			a_node.set_text( node_pair[1] );

			node_lists.add( a_node );			
		}

		return node_lists;
	}
	
	private void build_parent_children_relation( ArrayList node_list ){		
		ArrayList	 node_parent_children_relations	= create_information_list_by_category( this.node_data, CHILD_PARENT_RELATION );

		for ( Iterator _i = node_parent_children_relations.iterator(); _i.hasNext(); ){
			String node_parent_children_relation = (String)_i.next();
			//Debug.println( "node_parent_children_relation: " + node_parent_children_relation, 3 );
			
			String[]	child_parent_pair	= parse_a_pair_of_word( node_parent_children_relation, SEP );
			String 
				child_label		= child_parent_pair[0],
				parent_label	= child_parent_pair[1];

			//Debug.println( "parent_label: " + parent_label, 3 );
			//Debug.println( "child_label: " + child_label, 3 );

			Node
				parent	= retrieve_node_by_label( parent_label, node_list ),
				child	= retrieve_node_by_label( child_label, node_list );

			//Debug.println( "parent node: " + parent, 3 );
			//Debug.println( "child node: " + child, 3 );
			
			if ( child == null) {
				throw new App_Exception( "Invalid child node label ocurred when Clustered_Graph_Builder create_parent_children_relation for node" + parent_label + "-"+ child_label  + "!" );
			}

			if ( parent == null && ! parent_label.equals( "-" ) ){
				throw new App_Exception( "Invalid parent node label ocurred when Clustered_Graph_Builder create_parent_children_relation for node" + parent_label + "-"+ child_label  + "!" );
			}


			if ( parent != null && child != null ){
				parent.add_child(child);
				child.set_parent( parent );
				//Debug.println( "parent_children_relation Node type created!", 3 );
			}
		}
	}

	//build data section//=============================================================
	//write the data of @a_graph to @a_file
	public void build_data( Graph a_graph, String a_file_cp_name )  throws IOException	{				
		//detele existing file if there is
		File_Util.delete_file( a_file_cp_name );

		build_node_data( a_graph, a_file_cp_name );

		build_relation_data( a_graph, a_file_cp_name );
		
		build_edge_data( a_graph, a_file_cp_name );
	}
	///
	private void build_section_head( String data_file, String section_name )  throws IOException{
		File_Util.append_to_file( data_file, section_name );
	}
	
	private void build_section_end( String data_file, String section_name )  throws IOException{
		File_Util.append_to_file( data_file, comments + " finish building" + section_name + "\n");
	}

	private void build_node_data( Graph a_graph, String a_file_cp_name )  throws IOException{
		ArrayList nodes	= a_graph.find_nodes();

		build_section_head( a_file_cp_name, NODE );

		for ( Iterator _i =  nodes.iterator(); _i.hasNext(); ){
			Node	 node	 = (Node)_i.next();

			String
				label	= node.get_label(),
				text	= node.get_text();

			String
				info_to_write	= label + SEP + text;
			
			File_Util.append_to_file( a_file_cp_name, info_to_write );
		}	

		build_section_end( a_file_cp_name, NODE );		
	}

	private void build_relation_data( Graph a_graph, String a_file_cp_name )  throws IOException{
		ArrayList nodes	= a_graph.find_nodes();

		build_section_head( a_file_cp_name, CHILD_PARENT_RELATION );

		File_Util.append_to_file( a_file_cp_name, "0,-" );
		for ( Iterator _i =  nodes.iterator(); _i.hasNext(); ){
			Node		node	 = (Node)_i.next();

			String	 	label	= node.get_label();
			
			ArrayList children	= node.get_children();

			Debug.println( "extract " + node + " children: " + children, 3 );
			
			for (int i = 0 ; i < children.size(); i++ ){
				Node child	= (Node)children.get(i);

				Debug.println( "\t " + child , 3 );
				String child_label	= child.get_label();
				
				String	 	info_to_write	= child_label + SEP + label;
				
				File_Util.append_to_file( a_file_cp_name, info_to_write );
			}
		}	

		build_section_end( a_file_cp_name, CHILD_PARENT_RELATION );		
	}

	private void build_edge_data( Graph a_graph, String a_file_cp_name )  throws IOException{
		ArrayList edges	= a_graph.find_edges();

		build_section_head( a_file_cp_name, EDGE );
		
		for ( Iterator _i =  edges.iterator(); _i.hasNext(); ){
			String[] edge_labels	= (String[])_i.next();

			String
				from_label	= edge_labels[0],
				to_label		= edge_labels[1];

			String
				info_to_write	= from_label + SEP + to_label;
			
			File_Util.append_to_file( a_file_cp_name, info_to_write );
		}	

		build_section_end( a_file_cp_name, EDGE );		
	}
};

